#include "inputpc.h"
#include "list.h"

static IDirectInput8	*s_dinput = 0;

	

//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//	keyboard
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
ID_KEYBOARDPC::ID_KEYBOARDPC( INPUTDEVICE **ippme, HWND hWnd ) : ID_KEYBOARD(ippme)
{
	pDevice = 0;
	m_hWnd = hWnd;
	memset(keyState,0,sizeof(keyState));
	memset(keyMappings,0,sizeof(keyMappings));

	MapKey(	DIK_UP,			INPUT_UP		);
	MapKey(	DIK_DOWN,		INPUT_DOWN		);
	MapKey(	DIK_LEFT,		INPUT_LEFT		);
	MapKey(	DIK_RIGHT,		INPUT_RIGHT		);
	MapKey(	DIK_SPACE,		INPUT_BUTTON0	);
	MapKey(	DIK_LCONTROL,	INPUT_BUTTON1	);
	MapKey(	DIK_LSHIFT,		INPUT_BUTTON2	);
}

ID_KEYBOARDPC::~ID_KEYBOARDPC()
{
	if( pDevice )
	{
		pDevice->Unacquire();
		pDevice->Release();
		pDevice = 0;
	}
}

//--------------------------------------------------------
//	map a key
//--------------------------------------------------------
void ID_KEYBOARDPC::MapKey( u32 keyDefine, u32 bits )
{
	assert(keyDefine<countof(keyMappings));
	keyMappings[keyDefine] = bits;
}

//--------------------------------------------------------
//	create the keyboard device
//--------------------------------------------------------
bool ID_KEYBOARDPC::CreateDevice()
{
	HRESULT		hr;
	if( pDevice==0 )
	{
		hr = s_dinput->CreateDevice(GUID_SysKeyboard, &pDevice, NULL);
		if( pDevice!=0 )
		{
			pDevice->SetDataFormat(&c_dfDIKeyboard); 
			pDevice->SetCooperativeLevel(m_hWnd,DISCL_BACKGROUND|DISCL_NONEXCLUSIVE); 
			pDevice->Acquire(); 
		}
	}
	return (pDevice!=0);
}

//--------------------------------------------------------
//	process the keyboard device
//--------------------------------------------------------
void ID_KEYBOARDPC::Process()
{
	HRESULT		hr;
	u32			current = 0;
	u32			i;

	if( CreateDevice() )
	{
		hr = pDevice->GetDeviceState( sizeof(keyState),(LPVOID)&keyState);
		if( hr==DIERR_INPUTLOST )
		{
			hr = pDevice->Acquire(); 
			if( hr==DI_OK )	
				hr = pDevice->GetDeviceState( sizeof(keyState),(LPVOID)&keyState);
		}

		if( hr==DI_OK )
		{
			for( i=0;i<countof(keyMappings);i++ )
			{
				if( keyState[i]&128 )
					current |= keyMappings[i];
			}
		}
	}

	controls[CT_CURRENT] = current;
	INPUTDEVICE::Process();
}

//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//	mouse
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
ID_MOUSEPC::ID_MOUSEPC( INPUTDEVICE **ippme, HWND hWnd ) : ID_MOUSE(ippme)
{
	pDevice = 0;
	m_hWnd = hWnd;
	memset(&mouseState,0,sizeof(mouseState));
}

ID_MOUSEPC::~ID_MOUSEPC()
{
	if( pDevice )
	{
		pDevice->Unacquire();
		pDevice->Release();
		pDevice = 0;
	}
}

//--------------------------------------------------------
//	create the keyboard device
//--------------------------------------------------------
bool ID_MOUSEPC::CreateDevice()
{
	HRESULT		hr;
	if( pDevice==0 )
	{
		hr = s_dinput->CreateDevice(GUID_SysMouse, &pDevice, NULL);
		if( pDevice!=0 )
		{
			pDevice->SetDataFormat(&c_dfDIMouse); 
			pDevice->SetCooperativeLevel(m_hWnd,DISCL_BACKGROUND|DISCL_NONEXCLUSIVE); 
			pDevice->Acquire(); 
		}
	}
	return (pDevice!=0);
}

//--------------------------------------------------------
//	process the keyboard device
//--------------------------------------------------------
void ID_MOUSEPC::Process()
{
	HRESULT		hr;
	u32			current = 0;
	u32			i;

	if( CreateDevice() )
	{
		hr = pDevice->GetDeviceState( sizeof(mouseState),(LPVOID)&mouseState);
		if( hr==DIERR_INPUTLOST )
		{
			hr = pDevice->Acquire(); 
			if( hr==DI_OK )	
				hr = pDevice->GetDeviceState( sizeof(mouseState),(LPVOID)&mouseState);
		}

		if( hr==DI_OK )
		{
			for( i=0;i<countof(mouseState.rgbButtons);i++ )
			{
				if( mouseState.rgbButtons[i]&128 )
					current |= (INPUT_BUTTON0)<<i;
			}
		}
	}

	controls[CT_CURRENT] = current;
	INPUTDEVICE::Process();
}

//--------------------------------------------------------
//	get the mouse movement
//--------------------------------------------------------
void ID_MOUSEPC::GetMovement( s32 *pX, s32 *pY, s32 *pZ )
{
	if( pX )	*pX = mouseState.lX;
	if( pY )	*pY = mouseState.lY;
	if( pZ )	*pZ = mouseState.lZ;
}

//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//	input device class
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
INPUTDEVICE::INPUTDEVICE( INPUTDEVICE **ippme )
{
	UNILIST::Insert(this,ippme);
	memset(controls,0,sizeof(controls));
}
INPUTDEVICE::~INPUTDEVICE()
{
	UNILIST::Remove(this);
}
void INPUTDEVICE::Process()
{
	u32		change = controls[CT_CURRENT]^controls[CT_LAST];
	controls[CT_HELD]     = controls[CT_CURRENT] & controls[CT_LAST];
	controls[CT_PRESSED]  = change&controls[CT_CURRENT];
	controls[CT_RELEASED] = change&controls[CT_LAST];
	controls[CT_LAST]     = controls[CT_CURRENT];
}

//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//	input manager class
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
//--------------------------------------------------------
INPUTMGR::INPUTMGR()
{
	pDevices = 0;
}
INPUTMGR::~INPUTMGR()
{
	Uninit();
}

//--------------------------------------------------------
//--------------------------------------------------------
bool INPUTMGR::Init( HWND hWnd )
{
	HRESULT	err;
	err = DirectInput8Create(	(HINSTANCE)GetModuleHandle(NULL),
								DIRECTINPUT_VERSION,
								IID_IDirectInput8A,
								(void**)&s_dinput,
								0 );
	if( err==DI_OK )
	{
		new ID_KEYBOARDPC(&pDevices,hWnd);
		new ID_MOUSEPC(&pDevices,hWnd);
	}
	return (err==DI_OK);
}

//--------------------------------------------------------
//--------------------------------------------------------
void INPUTMGR::Uninit()
{
	while(pDevices)
		delete pDevices;
	if( s_dinput )
	{
		s_dinput->Release();
		s_dinput = 0;
	}
}
//--------------------------------------------------------
//--------------------------------------------------------
void INPUTMGR::Process()
{
	INPUTDEVICE *pdev;

	for( pdev=pDevices;pdev;pdev=UNILIST::GetNext(pdev) )
		pdev->Process();
}

//--------------------------------------------------------
//--------------------------------------------------------
ID_KEYBOARD *INPUTMGR::GetKeyboard()
{
	INPUTDEVICE *pdev;

	for( pdev=pDevices;pdev;pdev=UNILIST::GetNext(pdev) )
		if( pdev->IsKeyboard() )
			return pdev->IsKeyboard();
	return 0;
}
//--------------------------------------------------------
//--------------------------------------------------------
ID_MOUSE *INPUTMGR::GetMouse()
{
	INPUTDEVICE *pdev;

	for( pdev=pDevices;pdev;pdev=UNILIST::GetNext(pdev) )
		if( pdev->IsMouse() )
			return pdev->IsMouse();
	return 0;
}